#include "Util.h"
#include "Exceptions.h"
#include "tree/EmptyStatement.h"
#include <sstream>

string Util::Number2String(int iValue)
{
    ostringstream lOSS;
	lOSS.clear();
	lOSS << iValue;
	return lOSS.str();
}

string Util::ValueType2String(ValueType iType)
{
    switch(iType)
    {
        case LongInteger:       return "int";
        case Double:            return "double";
        case String:            return "string";
        case UserDefinedObject: return "object";
        case Boolean:           return "bool";
        case Array:             return "array";
        case Unresolved:        return "(unresolved)";
        case Undefined:         return "undefined";
    }

    return "(undefined type)";
}

string Util::BinaryOp2String(BinaryOperationType iOp)
{
    switch(iOp)
    {
        case Plus:              return "+";
        case Minus:             return "-";
        case Multiply:          return "*";
        case Divide:            return "/";
        case Modulo:            return "%";
        case Equal:             return "==";
        case NotEqual:          return "!=";
        case Less:              return "<";
        case Greater:           return ">";
        case LessOrEqual:       return "<=";
        case GreaterOrEqual:    return ">=";
        case And:               return "&&";
        case Or:                return "||";
    }

    return "(undefined operation)";
}

string Util::UnaryOp2String(UnaryOperationType iOp)
{
    switch(iOp)
    {
        case UnaryMinus:    return "-";
        case Negation:      return "!";
    }

    return "(undefined operation)";
}

string Util::BuiltInFunctionType2String(BuiltInFunctionType iFn)
{
    switch(iFn)
    {
        case ArrayFunction: return "array";
        case PrintFunction: return "print";
        default: return "!!! unrecognized built-in function !!!";
    }
}

int Util::LEBytes2Int(string iBytes)
{
    if(iBytes.length() != 4)
    {
        string lMessage = "LEBytes2Int: potrebuji 4 byty, obdrzeno: " + Util::Number2String(iBytes.length()); 
        throw BaseException(lMessage);
    }

    int lResult = 0;
    int lShiftBy = 0;

    for(int i = 0; i < 4; i++, lShiftBy += 8)
    {
        unsigned char lByte = iBytes[i];
        lResult = lResult | (lByte << lShiftBy);
    }

    return lResult;
}

bool Util::Byte2Bool(char iByte)
{
    if(iByte == 0)
        return false;
    else
        return true;
}

vector<char> Util::Int2LittleEndian(int iValue)
{
    vector<char> lResult;
    lResult.reserve(4);
    int lValue = iValue;

    for(int i = 0; i < 4; ++i)
    {
        char lC = lValue & 0xFF;    // vem nejnizsi byte...
        lResult.push_back(lC);      // ... dej ho na konec vysledku ...
        lValue = lValue >> 8;       // ... a cislo soupni doprava o jeden byte
    }

    return lResult;
}

FunctionDefinition* Util::BuildPredefinedFunction(string iName, unsigned int iParamCount)
{
    vector<Variable*> lInputVars;

    for(unsigned int i = 0; i < iParamCount; i++)
    {
        string lFakeVarName = "a" + Util::Number2String(i);
        lInputVars.push_back(new Variable(lFakeVarName));
    }

    FunctionDefinition* lDef = new FunctionDefinition(iName, lInputVars, new EmptyStatement(), true);
    lDef->SetBuiltInFunctionType(Other);
    return lDef;
}
